#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Windows应用分析器
"""

import os
import re
import struct
from pathlib import Path
from typing import Dict, List, Any, Optional, Set
from datetime import datetime

import pefile
from src.analyzers.base import BaseAnalyzer
from src.models.result import AnalysisResult, FrameworkInfo, AppInfo
from src.utils.logger import get_logger

class WindowsAnalyzer(BaseAnalyzer):
    """Windows应用程序分析器"""

    # Windows应用程序框架签名，用于识别应用程序使用的框架和技术栈
    FRAMEWORK_SIGNATURES = {
        "WPF": {
            "files": [r"\.xaml$", r"PresentationFramework\.dll$", r"PresentationCore\.dll$"],
            "patterns": [
                r"xmlns=\"http://schemas\.microsoft\.com/winfx/2006/xaml/presentation\"",
                r"System\.Windows\.Controls",
                r"System\.Windows\.Application"
            ],
            "category": "UI框架",
            "main_framework": True
        },
        "WinForms": {
            "files": [r"\.resx$", r"System\.Windows\.Forms\.dll$"],
            "patterns": [
                r"System\.Windows\.Forms",
                r"InitializeComponent\(\)",
                r"Windows\.Forms\.Form"
            ],
            "category": "UI框架",
            "main_framework": True
        },
        "UWP": {
            "files": [r"Package\.appxmanifest$", r"\.xbf$", r"Windows\.UI\.Xaml"],
            "patterns": [
                r"<uap:",
                r"Windows\.UI\.Xaml",
                r"ApplicationModel"
            ],
            "category": "UI框架",
            "main_framework": True
        },
        "Electron": {
            "files": [r"electron\.asar$", r"package\.json$", r"node_modules[\\/]electron"],
            "patterns": [
                r"electron\S*\.(exe|dll)$",
                r"\"electron\":",
                r"app\.on\('ready'"
            ],
            "category": "跨平台框架",
            "main_framework": True
        },
        "Qt": {
            "files": [r"Qt5\w+\.(dll|so)$", r"\.qml$", r"\.ui$"],
            "patterns": [
                r"#include <[QK]\w+>",
                r"QApplication",
                r"QObject",
                r"QWidget"
            ],
            "category": "跨平台框架",
            "main_framework": True
        },
        "Win32": {
            "files": [r"\.rc$", r"resource\.h$"],
            "patterns": [
                r"#include <windows\.h>",
                r"HWND",
                r"LPCWSTR",
                r"WndProc",
                r"RegisterClassW"
            ],
            "category": "原生API",
            "main_framework": True
        },
        ".NET Core": {
            "files": [r"runtimeconfig\.json$", r"\.deps\.json$", r"Microsoft\.NETCore\.App"],
            "patterns": [
                r"netcoreapp\d\.\d",
                r"\.NETCoreApp,Version=v",
                r"Microsoft\.NETCore\.App"
            ],
            "category": "运行时",
            "main_framework": False
        },
        ".NET Framework": {
            "files": [r"AssemblyInfo\.cs$", r"\.config$", r"\.csproj$"],
            "patterns": [
                r"<supportedRuntime version=\"v\d\.",
                r"<TargetFrameworkVersion>v\d\.",
                r"System\.(Threading|IO|Collections)"
            ],
            "category": "运行时",
            "main_framework": False
        },
        "SQLite": {
            "files": [r"sqlite\d?\.dll$", r"\.sqlite$", r"\.db$"],
            "patterns": [
                r"SQLite format 3\x00",
                r"using System.Data.SQLite",
                r"SQLiteConnection",
                r"sqlite3_"
            ],
            "category": "数据库",
            "main_framework": False
        },
        "CEF (Chromium Embedded Framework)": {
            "files": [r"cef\w*\.(dll|pak|bin)$", r"icudtl\.dat$", r"chrome_elf\.dll$"],
            "patterns": [
                r"cef_",
                r"CefSharp\.",
                r"chromium"
            ],
            "category": "Web引擎",
            "main_framework": False
        },
        "OpenGL": {
            "files": [r"opengl32\.dll$", r"glew\d+\.dll$"],
            "patterns": [
                r"glVertex",
                r"glBindBuffer",
                r"#include <GL/",
                r"OpenGL"
            ],
            "category": "图形API",
            "main_framework": False
        },
        "DirectX": {
            "files": [r"d3d\w*\.dll$", r"dxgi\.dll$"],
            "patterns": [
                r"Direct3D",
                r"D3D11",
                r"ID3D\w+",
                r"DirectX"
            ],
            "category": "图形API",
            "main_framework": False
        }
    }
    
    def __init__(self, app_path: str, config: dict = None, verbose: bool = False):
        """
        初始化Windows应用程序分析器
        
        Args:
            app_path: 应用程序路径
            config: 配置信息
            verbose: 是否输出详细日志
        """
        super().__init__(app_path, config, verbose)
        self.logger.info(f"初始化Windows应用程序分析器: {app_path}")
        
        # 合并配置和默认框架特征
        self.framework_signatures = self.FRAMEWORK_SIGNATURES.copy()
        if "frameworks" in self.config:
            for fw_name, fw_data in self.config["frameworks"].items():
                if fw_name in self.framework_signatures:
                    # 更新现有框架
                    for key, values in fw_data.items():
                        if key in self.framework_signatures[fw_name]:
                            self.framework_signatures[fw_name][key].extend(values)
                        else:
                            self.framework_signatures[fw_name][key] = values
                else:
                    # 添加新框架
                    self.framework_signatures[fw_name] = fw_data
    
    def analyze(self) -> AnalysisResult:
        """
        分析Windows应用程序，识别使用的框架和技术栈
        
        Returns:
            AnalysisResult: 分析结果
        """
        self.logger.info(f"开始分析Windows应用: {self.app_path}")
        
        app_path = Path(self.app_path)
        result = AnalysisResult(
            app_path=str(app_path),
            platform="Windows",
            analysis_time=datetime.now()
        )
        
        # 尝试检测应用程序信息
        app_info = self.detect_app_info()
        if app_info:
            result.app_name = app_info.name
            result.app_version = app_info.version
            result.metadata["app_identifier"] = app_info.identifier  # 添加标识符到元数据
            
            # 记录日志
            self.logger.info(f"应用信息: 名称={app_info.name}, 版本={app_info.version}, 标识符={app_info.identifier}")
        
        # 扫描应用程序文件类型
        extensions = ['.exe', '.dll', '.config', '.xaml', '.resx', '.cs', '.xml', '.manifest', '.json']
        files = self.scan_files(extensions)
        
        # 如果找不到文件，尝试搜索更多类型的文件
        if len(files) < 5:
            self.logger.info("找到的文件较少，尝试扫描所有文件...")
            all_files = self.scan_files([])  # 空列表表示扫描所有文件
            files.extend([f for f in all_files if f not in files])
            
            # 如果仍然找不到足够的文件，尝试直接搜索
            if len(files) < 5 and os.path.isdir(self.app_path):
                self.logger.info("尝试直接搜索目录内的所有文件...")
                for root, _, filenames in os.walk(self.app_path):
                    for filename in filenames:
                        file_path = Path(root) / filename
                        if file_path not in files:
                            files.append(file_path)
        
        self.logger.info(f"扫描到 {len(files)} 个文件，开始分析框架")
        
        # 对于Windows安装程序，尝试检查文件特征来识别使用的安装程序框架
        self._detect_installer_type(files, result)
        
        # 识别框架特征
        for framework_name, signature in self.framework_signatures.items():
            # 搜索签名特征
            matched_files = self.search_signatures(files, 
                                                 signature.get('files', []), 
                                                 signature.get('patterns', []))
            
            if matched_files:
                confidence = min(0.3 + (len(matched_files) * 0.1), 0.9)  # 根据匹配文件数量增加信心值，最高0.9
                
                framework_info = FrameworkInfo(
                    name=framework_name,
                    confidence=confidence,
                    features=[],  # 特征在后续处理中可能会添加
                    files=matched_files[:5],  # 只保留前5个文件作为示例
                    category=signature.get('category', '其他'),  # 使用新的类别属性
                    is_main=signature.get('main_framework', False)  # 使用新的主框架属性
                )
                
                # 为不同框架添加特定特征
                if framework_name == "WPF":
                    framework_info.features.append("XAML界面布局")
                elif framework_name == "WinForms":
                    framework_info.features.append("基于控件的窗体设计")
                elif framework_name == "UWP":
                    framework_info.features.append("Universal Windows Platform应用")
                elif framework_name == "Electron":
                    framework_info.features.append("使用Web技术构建桌面应用")
                elif framework_name == "Qt":
                    framework_info.features.append("跨平台C++应用程序框架")
                else:
                    framework_info.features.append(f"{framework_name}技术特征")
                
                result.add_framework(framework_info)
                self.logger.info(f"检测到框架: {framework_name}, 信心值: {confidence:.2f}")
        
        # 如果没有检测到任何框架，尝试添加一个通用框架
        if len(result.frameworks) == 0:
            self.logger.info("未检测到特定框架，添加通用Windows原生框架")
            generic_framework = FrameworkInfo(
                name="Windows Native Application",
                confidence=0.5,
                features=["Windows可执行程序"],
                files=[str(f) for f in files[:5]] if files else [],
                category="原生应用",
                is_main=True
            )
            result.add_framework(generic_framework)
        
        self.logger.info(f"分析完成，共检测到 {len(result.frameworks)} 个框架")
        return result
    
    def detect_app_info(self) -> AppInfo:
        """
        尝试从可执行文件或配置文件中提取应用程序信息
        
        Returns:
            AppInfo: 应用程序信息对象
        """
        app_name = None
        app_version = None
        app_path = Path(self.app_path)
        
        # 首先检查是否为 UWP 应用，查找 AppxManifest.xml
        appx_manifest = list(app_path.glob("**/AppxManifest.xml"))
        if appx_manifest:
            try:
                with open(appx_manifest[0], 'r', encoding='utf-8') as f:
                    content = f.read()
                    
                # 提取 Identity Name 和 Version
                name_match = re.search(r'Identity.*?Name="([^"]+)"', content)
                version_match = re.search(r'Identity.*?Version="([^"]+)"', content)
                display_name_match = re.search(r'DisplayName="([^"]+)"', content)
                
                if name_match:
                    app_name = display_name_match.group(1) if display_name_match else name_match.group(1)
                if version_match:
                    app_version = version_match.group(1)
                    
                return AppInfo(
                    name=app_name or app_path.stem,
                    version=app_version,
                    platform="Windows"
                )
            except Exception as e:
                self.logger.error(f"读取AppxManifest失败: {e}")
        
        # 尝试从 .exe 文件中提取版本信息
        exe_files = list(app_path.glob("**/*.exe"))
        main_exe = None
        
        # 如果 app_path 本身是 .exe 文件，直接使用
        if app_path.suffix.lower() == '.exe':
            main_exe = app_path
        # 否则尝试找到主 .exe 文件
        elif exe_files:
            # 假设第一个 .exe 或名称与目录相同的 .exe 是主程序
            main_exe = exe_files[0]
            for exe in exe_files:
                if exe.stem.lower() == app_path.name.lower():
                    main_exe = exe
                    break
        
        if main_exe:
            try:
                # 提取 .exe 文件的版本信息
                app_name = main_exe.stem
                
                # 简单读取 PE 文件头部，尝试提取版本信息
                # 这里提供的是简化版，实际可能需要完整的 PE 解析器
                try:
                    with open(main_exe, 'rb') as f:
                        # 读取 DOS 头部
                        data = f.read(2)
                        if data == b'MZ':  # MZ 头部标识
                            f.seek(60)  # 转到 PE 签名偏移位置
                            pe_offset = struct.unpack('<I', f.read(4))[0]
                            f.seek(pe_offset)
                            if f.read(4) == b'PE\x00\x00':  # PE 签名
                                # 跳过文件头到可选头部
                                f.seek(pe_offset + 24)
                                magic = struct.unpack('<H', f.read(2))[0]
                                # 跳过可选头部到数据目录
                                if magic == 0x10b:  # PE32
                                    f.seek(pe_offset + 24 + 96)
                                elif magic == 0x20b:  # PE32+
                                    f.seek(pe_offset + 24 + 112)
                                
                                # 读取资源目录 RVA 和大小
                                resource_rva = struct.unpack('<I', f.read(4))[0]
                                if resource_rva > 0:
                                    # 这里我们应该解析资源部分来获取版本信息
                                    # 但这需要更复杂的PE解析逻辑，简化版这里省略
                                    app_version = "1.0.0"  # 默认版本
                except Exception as e:
                    self.logger.error(f"解析PE文件失败: {e}")
                    app_version = "未知"
            except Exception as e:
                self.logger.error(f"提取应用信息失败: {e}")
        
        return AppInfo(
            name=app_name or app_path.stem,
            version=app_version,
            platform="Windows"
        )
    
    def identify_frameworks(self, files: List[Path]) -> Dict[str, Dict[str, Any]]:
        """
        识别Windows应用使用的框架
        
        Args:
            files: 文件路径列表
            
        Returns:
            识别到的框架信息字典
        """
        frameworks = {}
        dll_files = []
        text_files = []
        
        # 过滤文件类型
        for file in files:
            if file.suffix.lower() == '.dll' or file.suffix.lower() == '.exe':
                dll_files.append(file)
            elif self._is_text_file(file):
                text_files.append(file)
        
        # 记录发现的特征
        found_features = {fw: set() for fw in self.framework_signatures.keys()}
        found_files = {fw: set() for fw in self.framework_signatures.keys()}
        
        # 分析DLL文件名
        for dll in dll_files:
            dll_name = dll.name.lower()
            
            for fw_name, fw_data in self.framework_signatures.items():
                if "dlls" in fw_data:
                    for sig_dll in fw_data["dlls"]:
                        if sig_dll.lower() == dll_name:
                            found_features[fw_name].add(f"Found DLL: {dll_name}")
                            found_files[fw_name].add(str(dll))
                
                if "files" in fw_data:
                    for sig_file in fw_data["files"]:
                        if sig_file.lower() == dll_name:
                            found_features[fw_name].add(f"Found file: {dll_name}")
                            found_files[fw_name].add(str(dll))
        
        # 分析文本文件内容
        for text_file in text_files:
            try:
                with open(text_file, 'r', encoding='utf-8', errors='ignore') as f:
                    content = f.read()
                    
                    for fw_name, fw_data in self.framework_signatures.items():
                        # 检查命名空间
                        if "namespaces" in fw_data:
                            for namespace in fw_data["namespaces"]:
                                if namespace in content:
                                    found_features[fw_name].add(f"Namespace: {namespace}")
                                    found_files[fw_name].add(str(text_file))
                        
                        # 检查模式
                        if "patterns" in fw_data:
                            for pattern in fw_data["patterns"]:
                                if pattern in content:
                                    found_features[fw_name].add(f"Pattern: {pattern}")
                                    found_files[fw_name].add(str(text_file))
            except Exception as e:
                self.logger.debug(f"分析文件 {text_file} 时出错: {e}")
        
        # 计算置信度并构建结果
        for fw_name, features in found_features.items():
            if features:
                # 根据特征数量计算置信度
                base_confidence = min(len(features) * 0.2, 0.9)
                # 有些框架更具特异性，提高置信度
                if fw_name in ["Electron", "Qt", "UWP"]:
                    confidence = min(base_confidence + 0.1, 1.0)
                else:
                    confidence = base_confidence
                
                frameworks[fw_name] = {
                    "confidence": confidence,
                    "features": list(features),
                    "files": list(found_files[fw_name]),
                    "version": self._detect_framework_version(fw_name, found_files[fw_name])
                }
        
        # 检查依赖关系，处理一些常见的冲突
        if "WPF" in frameworks and "WinForms" in frameworks:
            # 如果WPF置信度高，降低WinForms置信度
            if frameworks["WPF"]["confidence"] > frameworks["WinForms"]["confidence"]:
                frameworks["WinForms"]["confidence"] *= 0.7
            
        if ".NET Core" in frameworks and ".NET Framework" in frameworks:
            # 检查哪个更可能
            if frameworks[".NET Core"]["confidence"] > frameworks[".NET Framework"]["confidence"]:
                frameworks[".NET Framework"]["confidence"] *= 0.6
            else:
                frameworks[".NET Core"]["confidence"] *= 0.6
        
        # 过滤低置信度框架
        return {k: v for k, v in frameworks.items() if v["confidence"] > 0.3}
    
    def _detect_framework_version(self, framework_name: str, files: Set[str]) -> Optional[str]:
        """
        尝试检测框架版本
        
        Args:
            framework_name: 框架名称
            files: 相关文件路径集合
            
        Returns:
            框架版本或None
        """
        # 根据不同框架使用不同的版本检测方法
        if framework_name == "Electron":
            return self._detect_electron_version(files)
        elif framework_name in [".NET Core", ".NET Framework"]:
            return self._detect_dotnet_version(files)
        elif framework_name == "Qt":
            return self._detect_qt_version(files)
        
        return None
    
    def _detect_electron_version(self, files: Set[str]) -> Optional[str]:
        """检测Electron版本"""
        for file in files:
            # 尝试从package.json提取
            if "package.json" in file:
                try:
                    import json
                    with open(file, 'r', encoding='utf-8') as f:
                        data = json.load(f)
                        if "devDependencies" in data and "electron" in data["devDependencies"]:
                            return data["devDependencies"]["electron"].replace("^", "")
                        if "dependencies" in data and "electron" in data["dependencies"]:
                            return data["dependencies"]["electron"].replace("^", "")
                except Exception:
                    pass
            
            # 尝试从electron.dll提取版本信息
            if "electron.dll" in file.lower():
                try:
                    pe = pefile.PE(file)
                    for fileinfo in pe.FileInfo:
                        if hasattr(fileinfo, 'StringTable'):
                            for st in fileinfo.StringTable:
                                for k, v in st.entries.items():
                                    if k.decode('utf-8') == 'ProductVersion':
                                        return v.decode('utf-8')
                except Exception:
                    pass
        
        return None
    
    def _detect_dotnet_version(self, files: Set[str]) -> Optional[str]:
        """检测.NET版本"""
        for file in files:
            if file.lower().endswith('.dll') or file.lower().endswith('.exe'):
                try:
                    from src.utils.dotnet import get_assembly_version
                    return get_assembly_version(file)
                except ImportError:
                    # 简化的.NET版本检测方法
                    try:
                        pe = pefile.PE(file)
                        for fileinfo in pe.FileInfo:
                            if hasattr(fileinfo, 'StringTable'):
                                for st in fileinfo.StringTable:
                                    for k, v in st.entries.items():
                                        if k.decode('utf-8') == 'Assembly Version':
                                            return v.decode('utf-8')
                    except Exception:
                        pass
        
        return None
    
    def _detect_qt_version(self, files: Set[str]) -> Optional[str]:
        """检测Qt版本"""
        # 从Qt核心DLL名称推断版本
        for file in files:
            file_lower = file.lower()
            if "qt6core" in file_lower:
                return "6.x"
            elif "qt5core" in file_lower:
                return "5.x"
            elif "qtcore4" in file_lower:
                return "4.x"
        
        return None
    
    def _detect_installer_type(self, files: List[Path], result: AnalysisResult) -> None:
        """
        检测Windows安装程序类型
        
        Args:
            files: 扫描到的文件列表
            result: 分析结果对象
        """
        # 文件名和内容关键字
        installer_signatures = {
            "Inno Setup": {
                "files": [r"unins000\.exe$", r"unins000\.dat$", r"_iu14\.exe$"],
                "patterns": ["Inno Setup", "ISSelfExtractData", "[Setup]"]
            },
            "NSIS": {
                "files": [r"uninstall\.exe$", r"\.nsh$"],
                "patterns": ["Nullsoft Install System", "NSIS", "$INSTDIR"]
            },
            "WiX Toolset": {
                "files": [r"\.wixobj$", r"\.wxs$"],
                "patterns": ["WiX Toolset", "Windows Installer XML", "<Wix"]
            },
            "InstallShield": {
                "files": [r"Setup\.ini$", r"Setup\.inx$"],
                "patterns": ["InstallShield", "INSTALLSHIELD", "ISSetup"]
            },
            "Advanced Installer": {
                "files": [r"\.aip$"],
                "patterns": ["Advanced Installer", "ADVANCEDINSTALLER"]
            },
            "MSI Installer": {
                "files": [r"\.msi$"],
                "patterns": ["Windows Installer", "MSI", "InstallExecuteSequence"]
            }
        }
        
        # 检查安装程序特征
        for installer_name, signature in installer_signatures.items():
            matched_files = self.search_signatures(files, 
                                               signature.get('files', []), 
                                               signature.get('patterns', []))
            
            if matched_files:
                confidence = min(0.4 + (len(matched_files) * 0.1), 0.9)
                
                installer_info = FrameworkInfo(
                    name=f"{installer_name}",
                    confidence=confidence,
                    features=[f"{installer_name}安装程序"],
                    files=matched_files[:3],
                    category="安装程序",
                    is_main=False
                )
                
                result.add_framework(installer_info)
                self.logger.info(f"检测到安装程序类型: {installer_name}, 信心值: {confidence:.2f}")
                
                # 只要匹配到一种安装程序类型就跳出循环
                # break
        
        # 还可以尝试检测一些常见的打包工具
        self._detect_packaging_tools(files, result)
    
    def _detect_packaging_tools(self, files: List[Path], result: AnalysisResult) -> None:
        """
        检测Windows应用打包工具
        
        Args:
            files: 扫描到的文件列表
            result: 分析结果对象
        """
        # 打包工具特征
        packaging_signatures = {
            "Electron": {
                "files": [r"electron\.asar$", r"app\.asar$", r"electron\.exe$"],
                "patterns": ["ELECTRON", "electron.js", "Electron Framework"]
            },
            "MSIX Packaging": {
                "files": [r"AppxManifest\.xml$", r"\.appx$", r"\.msix$"],
                "patterns": ["<Identity", "<Applications", "<Capabilities"]
            },
            "Click Once": {
                "files": [r"\.application$", r"\.manifest$"],
                "patterns": ["asmv1", "ClickOnce", "assemblyIdentity"]
            },
            "App-V": {
                "files": [r"\.appv$"],
                "patterns": ["App-V", "Microsoft Application Virtualization"]
            },
            "Squirrel.Windows": {
                "files": [r"Update\.exe$", r"\.nupkg$"],
                "patterns": ["Squirrel", "NuGet", "Update.exe"]
            },
            "WinRAR SFX": {
                "files": [r"\.sfx$", r"sfxcmd$"],
                "patterns": ["WinRAR", "SFX", "RAR!"]
            }
        }
        
        # 检查打包工具特征
        for tool_name, signature in packaging_signatures.items():
            matched_files = self.search_signatures(files, 
                                               signature.get('files', []), 
                                               signature.get('patterns', []))
            
            if matched_files:
                confidence = min(0.4 + (len(matched_files) * 0.1), 0.9)
                
                packaging_info = FrameworkInfo(
                    name=f"{tool_name}",
                    confidence=confidence,
                    features=[f"{tool_name}打包工具"],
                    files=matched_files[:3],
                    category="打包工具",
                    is_main=False
                )
                
                result.add_framework(packaging_info)
                self.logger.info(f"检测到打包工具: {tool_name}, 信心值: {confidence:.2f}")
        
        # 使用文件内容/二进制特征检测
        self._detect_binary_signatures(files, result)
    
    def _detect_binary_signatures(self, files: List[Path], result: AnalysisResult) -> None:
        """
        通过二进制特征检测应用
        
        Args:
            files: 扫描到的文件列表
            result: 分析结果对象
        """
        try:
            import magic
            # 优先检查exe文件
            exe_files = [f for f in files if f.suffix.lower() == '.exe']
            
            for exe_file in exe_files[:5]:  # 限制检查的文件数量
                try:
                    # 获取文件类型
                    file_type = magic.from_file(str(exe_file))
                    self.logger.info(f"文件 {exe_file.name} 类型: {file_type}")
                    
                    # 通过文件类型识别框架
                    if "PE32" in file_type:
                        if ".NET" in file_type or "assembly" in file_type:
                            dot_net_info = FrameworkInfo(
                                name=".NET Framework",
                                confidence=0.8,
                                features=["基于.NET Framework的Windows应用"],
                                files=[str(exe_file)],
                                category="运行时",
                                is_main=True
                            )
                            result.add_framework(dot_net_info)
                            self.logger.info(f"通过二进制特征检测到: .NET Framework")
                        
                        if "GUI" in file_type:
                            win32_info = FrameworkInfo(
                                name="Win32 GUI",
                                confidence=0.7,
                                features=["Windows图形用户界面应用"],
                                files=[str(exe_file)],
                                category="UI框架",
                                is_main=False
                            )
                            result.add_framework(win32_info)
                            
                        if "console" in file_type.lower():
                            console_info = FrameworkInfo(
                                name="Console Application",
                                confidence=0.7,
                                features=["命令行控制台应用"],
                                files=[str(exe_file)],
                                category="应用类型",
                                is_main=False
                            )
                            result.add_framework(console_info)
                except Exception as e:
                    self.logger.error(f"分析文件 {exe_file} 时出错: {e}")
                    
        except ImportError:
            self.logger.warning("未找到python-magic库，跳过二进制特征检测") 
